﻿using Fast2Jenkins.Jenkins;
using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;
using Windows.Storage;
using Windows.Security.Authentication.Web;
using System.Net;
using System.Net.Http;

namespace Fast2Jenkins.Helper
{
    /// <summary>
    /// Singleotn handling request to data and parsing it into objects and such. 
    /// </summary>
    public sealed class JenkinsParser
    {

        private static String baseUri = String.Empty;
        private static Boolean isSecure = false;
        private static String username = String.Empty;
        private static String password = String.Empty;

        /// <summary>
        /// Get all available views and fill them with available jobs. 
        /// </summary>
        /// <param name="url">The base URL to your Jenkins instance. Eg. "http://www.mycompany.com/jenkins".</param>
        /// <param name="username">Leave blank if no authentication required.</param>
        /// <param name="password"></param>
        /// <returns>A key/value store of views with their jobs.</returns>
        public static async Task<Dictionary<View, List<Job>>> Parse(String url, String username, String password)
        {
            Dictionary<View, List<Job>> jobsInViews = new Dictionary<View, List<Job>>();

            // Must end in slash
            if (!url.EndsWith("/")) {
                url += "/";
            }
            JenkinsParser.baseUri = url;

            // If username is specifiec then we must authenticate
            if (String.IsNullOrEmpty(username))
            {
                isSecure = false;
            }
            else
            {
                JenkinsParser.username = username;
                JenkinsParser.password = password;
                isSecure = true;
            }

            List<View> views = await GetViews();
            foreach (View view in views)
            {
                List<Job> jobs = await GetJobs(view);
                jobsInViews.Add(view, jobs);
            }

            return jobsInViews;
        }

        /// <summary>
        /// Takes out all available Views in Jenkins. 
        /// </summary>
        /// <returns>A lite of View objects</returns>
        private static async Task<List<View>> GetViews()
        {
            List<View> viewsList = new List<View>();

            String VIEWS_URI = baseUri + "api/xml?wrapper=views&xpath=/hudson/view";

            var request = WebRequest.CreateHttp(new Uri(VIEWS_URI));
            request.Method = "GET";

            if (isSecure)
            {
                request.Credentials = new NetworkCredential(username, password);
                request.Headers["Authorization"] = String.Format("Basic {0}:{1}", username, password);
            }

            // Request
            var response = await request.GetResponseAsync() as HttpWebResponse;
            var responseStream = new StreamReader(response.GetResponseStream());
            var responseData = await responseStream.ReadToEndAsync();

            // Parse XML into objects
            var document = XDocument.Parse(responseData);
            var viewObjects = from view in document.Descendants("view")
                              select new View()
                              {
                                  Name = view.Element("name").Value,
                                  Url = view.Element("url").Value
                              };

            viewsList.AddRange(viewObjects);

            return viewsList;
        }

        /// <summary>
        /// Takes out all Jobs in current view.
        /// </summary>
        /// <param name="view">The View of where to takes Jobs from.</param>
        /// <returns>A list of jobs</returns>
        private static async Task<List<Job>> GetJobs(View view)
        {
            List<Job> jobsList = new List<Job>();

            // For some reason the primary view doesn't have a proper URI.
            if (view.Url.Equals(baseUri))
            {
                view.Url += "view/" + view.Name + "/";
            }

            String JOBS_URI = view.Url + "api/xml?wrapper=jobs&xpath=/listView/job";

            var request = WebRequest.CreateHttp(new Uri(JOBS_URI));
            request.Method = "GET";
            
            if (isSecure)
            {
                request.Credentials = new NetworkCredential(username, password);
                request.Headers["Authorization"] = String.Format("Basic {0}:{1}", username, password);
            }

            // Request
            var response = await request.GetResponseAsync() as HttpWebResponse;
            var responseStream = new StreamReader(response.GetResponseStream());
            var responseData = await responseStream.ReadToEndAsync();

            // Parse XML into objects
            var document = XDocument.Parse(responseData);
            var jobsObjects = from job in document.Descendants("job")
                              select new Job()
                              {
                                  Name = job.Element("name").Value, 
                                  Url = job.Element("url").Value, 
                                  Color = job.Element("color").Value
                              };

            jobsList.AddRange(jobsObjects);

            return jobsList;
        }

    }
}
